package com.springBoot.service.impl;

import com.springBoot.commonClass.FieldItem;
import com.springBoot.commonClass.PostNewFile;
import com.springBoot.commonClass.Utils;
import com.springBoot.entity.BaseEntity;
import com.springBoot.entity.DataEntity;
import com.springBoot.entity.FieldsEntity;
import com.springBoot.entity.ObjectsEntity;
import com.springBoot.entity.union.ObjUnionFieldsEntity;
import com.springBoot.exception.BusinessFailureException;
import com.springBoot.repository.DataRepository;
import com.springBoot.repository.FieldsRepository;
import com.springBoot.repository.ObjectsRepository;
import com.springBoot.repository.union.ObjUnionFieldsRepository;
import com.springBoot.service.FileOperationService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.Future;

@Service
public class FileOperationServiceImpl implements FileOperationService {

    @Autowired
    private ObjectsRepository objRepository;
    @Autowired
    private FieldsRepository fieldsRepository;
    @Autowired
    private DataRepository dataRepository;
    @Autowired
    private ObjUnionFieldsRepository objUnionFieldsRepository;

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public Future<PostNewFile> insertNewFile(PostNewFile newFile) {
        Long startTs = System.currentTimeMillis();
//        Thread thread = new Thread();
        if(newFile.getObjId() == null){
            throw new BusinessFailureException();
        }
        String lastModifiedBy = newFile.getLastModifiedBy();
        ObjectsEntity objectsEntity = new ObjectsEntity();
        objectsEntity.setObjId(newFile.getObjId());
        boolean ifExists = objRepository.selectByParams(objectsEntity).size() > 0;
        if(ifExists){
            return updateFile(newFile);
        }else{
            //给前台赋objId
            newFile.setObjId(Utils.getUuid());
            List<FieldItem> fieldNameList = new ArrayList<>();
            List<FieldsEntity> fieldsEntityList = newFile.getFieldList();
            List<Map<String, String>> dataList = newFile.getDataList();
            List<FieldsEntity> newFieldsList = new ArrayList<>();

            //插入obj表
            BeanUtils.copyProperties(newFile, objectsEntity);
//            this.rebuildBaseEntity(objectsEntity, newFile);
            objectsEntity.setCreateDateTime(LocalDateTime.now());
            int objRes = objRepository.insert(objectsEntity);
            //插入field表
            Integer modifiedColumns = 0;
            for(FieldsEntity fEntity: fieldsEntityList){

//                BeanUtils.copyProperties(newFile, fEntity);
                this.rebuildBaseEntity(fEntity, newFile);
                String mapperName = "value" + fEntity.getFieldNum();
                fEntity.setMapperName(mapperName);
                fEntity.setFieldId(Utils.getUuid());
                fieldNameList.add(new FieldItem(fEntity.getLabel(), mapperName));
                //插入field
                fEntity.setCreateDateTime(LocalDateTime.now());
                Integer column = fieldsRepository.insert(fEntity);
                modifiedColumns += column;
                newFieldsList.add(fEntity);
            }
            newFile.setModifiedColumns(modifiedColumns);

            //插入data表
            Integer modifiedRows = 0;
            List<DataEntity> insertData = new ArrayList<>();
            Integer length = 0;
            Long mid = System.currentTimeMillis();
            for(Map<String, String> data: dataList){
                DataEntity dataEntity = new DataEntity();
                dataEntity.setDataId(Utils.getUuid());
                this.rebuildBaseEntity(dataEntity, newFile);
                for(FieldItem field:fieldNameList){
                    Utils.setFieldValueByName(field.getMapperName(), dataEntity, data.get(field.getFiledName()));
                }
                rebuildData(data, dataEntity);
                insertData.add(dataEntity);
                length++;
                if(length > 3000) {
                    //插入data
                    Integer row = dataRepository.batchInsert(insertData);
                    modifiedRows += row;
                    length = 0;
                    insertData = new ArrayList<>();
                }
            }
            //插入data
            Integer row = dataRepository.batchInsert(insertData);
            modifiedRows += row;
            newFile.setModifiedRows(modifiedRows);

            //整理数据
            newFile.setFieldList(newFieldsList);
//            return newFile;
            return new AsyncResult<>(newFile);
        }

    }

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public Future<PostNewFile> updateFile(PostNewFile newFile) {
        List<FieldItem> fieldNameList = new ArrayList<>();
        List<FieldsEntity> fieldsEntityList = newFile.getFieldList();
        List<Map<String, String>> dataList = newFile.getDataList();
        List<DataEntity> res = new ArrayList<>();
        List<FieldsEntity> newFieldsList = new ArrayList<>();

        //更新objects
        ObjectsEntity objectsEntity = new ObjectsEntity();
        BeanUtils.copyProperties(newFile, objectsEntity);
//        this.rebuildBaseEntity(objectsEntity, newFile);
        objectsEntity.setLastModifiedDateTime(LocalDateTime.now());
        objRepository.update(objectsEntity);

        //更新fields
        Integer modifiedColumns = 0;
        for(FieldsEntity fEntity: fieldsEntityList){
            String mapperName = "value" + fEntity.getFieldNum();
            fEntity.setMapperName(mapperName);
            fEntity.setLastModifiedDateTime(LocalDateTime.now());
            fieldNameList.add(new FieldItem(fEntity.getLabel(), mapperName));
            //插入field
            Integer column = fieldsRepository.update(fEntity);
            modifiedColumns += column;
        }
        newFile.setModifiedColumns(modifiedColumns);

        //更新data
        Integer modifiedRows = 0;
        for(Map<String, String> data: dataList){
            DataEntity dataEntity = new DataEntity();
            dataEntity.setDataId(data.get("dataId"));
            dataEntity.setOwnerId(data.get("ownerId"));
            dataEntity.setObjId(data.get("objId"));
            dataEntity.setOrgId(data.get("orgId"));
            dataEntity.setCreateBy(data.get("createBy"));
            dataEntity.setLastModifiedBy(data.get("lastModifiedBy"));
//            dataEntity.setDataRow(Integer.parseInt(data.get("row")));
            for(FieldItem field:fieldNameList){
                Utils.setFieldValueByName(field.getMapperName(), dataEntity, data.get(field.getFiledName()));
            }
            //插入data
            Integer row = dataRepository.update(dataEntity);
            modifiedRows += row;
        }
        newFile.setModifiedRows(modifiedRows);
//        return newFile;
        return new AsyncResult<>(newFile);
    }

    @Override
    @Async
    public Future<PostNewFile> querySingleFile(ObjectsEntity obj) {
        List<ObjUnionFieldsEntity> s =  objUnionFieldsRepository.selectObjUnionField(obj);
        if(s.size() < 1){
            throw new BusinessFailureException(false);
        }
         ObjUnionFieldsEntity unionFields =s.get(0);

         PostNewFile newFile = new PostNewFile();
         BeanUtils.copyProperties(unionFields, newFile);
         DataEntity params = new DataEntity();
         List<Map<String, String>> dataList = new ArrayList<>();
         params.setObjId(unionFields.getObjId());
         List<DataEntity> dataEntityList = dataRepository.selectByParams(params);
         for(DataEntity d: dataEntityList){
             Map<String, String> dataMap = new HashMap<>();
             //取值
             for(FieldsEntity field: unionFields.getFieldList()){
                 String value = Utils.getFieldValueByName(field.getMapperName(), d);
                 if(value != null){
                     dataMap.put(field.getLabel(), value);
                 }
             }
             rebuildData(dataMap, d);
             dataList.add(dataMap);
         }
         newFile.setDataList(dataList);
         newFile.setFieldList(unionFields.getFieldList());
//         return newFile;
        return new AsyncResult<>(newFile);
    }

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void deleteSingleFile(ObjectsEntity obj) {
        if(obj.getObjId() == null){
            throw new BusinessFailureException(false);
        }
//        String objId = obj.getObjId();
        //删除obj
        objRepository.delete(obj);
        //删除字段
        FieldsEntity fieldsEntity = new FieldsEntity();
        rebuildChangedBaseEntity(fieldsEntity, obj);
        fieldsRepository.batchDelete(fieldsEntity);

        //删除数据
        DataEntity dataEntity = new DataEntity();
        rebuildChangedBaseEntity(dataEntity, obj);
        List<DataEntity> dataEntityList = new ArrayList<>();
        dataEntityList.add(dataEntity);
        dataRepository.batchDeleteWithObjId(dataEntityList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyFileName(ObjectsEntity objectsEntity) {
        this.objRepository.update(objectsEntity);
    }

    private void rebuildData(Map<String, String> dataMap, DataEntity d){
        dataMap.put("ownerId", d.getOwnerId());
        dataMap.put("orgId", d.getOrgId());
        dataMap.put("objId", d.getObjId());
        dataMap.put("dataId", d.getDataId());
//        dataMap.put("row", d.getRow().toString());
        dataMap.put("createBy", d.getCreateBy());
        dataMap.put("createDateTime", d.getCreateDateTime().toString());
        dataMap.put("lastModifiedBy", d.getLastModifiedBy());
        dataMap.put("lastModifiedDateTime", d.getLastModifiedDateTime().toString());
    }

    private void rebuildBaseEntity(BaseEntity entity, PostNewFile file){
        entity.setCreateBy(file.getCreateBy());
        entity.setLastModifiedBy(file.getLastModifiedBy());
        entity.setOrgId(file.getOrgId());
        entity.setObjId(file.getObjId());
        entity.setOwnerId(file.getOwnerId());
    }

    public void rebuildChangedBaseEntity(BaseEntity a, BaseEntity b){
        a.setOwnerId(b.getOwnerId());
        a.setOrgId(b.getOrgId());
        a.setObjId(b.getObjId());
        a.setLastModifiedBy(b.getLastModifiedBy());
        a.setLastModifiedDateTime(LocalDateTime.now());
    }
}
